package br.com.jdobjs.core;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.Resource;
import org.drools.io.ResourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import bsh.EvalError;
import bsh.Interpreter;

public class DefaultRuleSecurityConfig implements RuleSecurityConfig {

	private static final Logger logger = LoggerFactory
			.getLogger(DefaultRuleSecurityConfig.class);
	private static final String CONFIG_BSH = "jdobjs.config.bsh";
	private static final String DRL = "jdobjs.drl";

	private UserCredentialsResolver userCredentialsResolver;
	private KnowledgeBase knowledgeBase;

	public DefaultRuleSecurityConfig() {
		super();
		loadConfig();
		if (userCredentialsResolver == null) {
			userCredentialsResolver = new EmptyUserCredentialsResolver();
		}
		if (knowledgeBase == null) {
			loadKnowledgeBaseFromDRLFile();
		}
	}

	protected void loadKnowledgeBaseFromDRLFile() {
		KnowledgeBuilder kbuilder = KnowledgeBuilderFactory
				.newKnowledgeBuilder();

		Resource resource = ResourceFactory.newClassPathResource(DRL,
				DefaultRuleSecurityConfig.class);
		if (resource == null) {
			knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
			logger.info("Empty knowledge base loaded.");
		} else {
			kbuilder.add(resource, ResourceType.DRL);
			if (kbuilder.hasErrors()) {
				throw new RuleSecurityConfigurationException(kbuilder
						.getErrors());
			}

			knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
			knowledgeBase.addKnowledgePackages(kbuilder.getKnowledgePackages());

			logger.info("Knowledge base in {} properly loaded.", DRL);
		}
	}

	public UserCredentialsResolver getUserCredentialsResolver() {
		return userCredentialsResolver;
	}

	public void setUserCredentialsResolver(
			UserCredentialsResolver userCredentialsResolver) {
		this.userCredentialsResolver = userCredentialsResolver;
	}

	public KnowledgeBase getKnowledgeBase() {
		return knowledgeBase;
	}

	public void setKnowledgeBase(KnowledgeBase knowledgeBase) {
		this.knowledgeBase = knowledgeBase;
	}

	protected void loadConfig() {
		URL configBshUrl = RuleSecurityConfig.class.getClassLoader()
				.getResource(CONFIG_BSH);
		if (configBshUrl == null) {
			logger
					.info(
							"The configuration BSH file {} could not be found on the classpath. The default configuration will be loaded.",
							CONFIG_BSH);
		} else {
			InputStreamReader reader = null;
			try {
				reader = new InputStreamReader(configBshUrl.openStream());

				Interpreter interpreter = new Interpreter();

				interpreter.set("config", this);

				interpreter.eval(reader);
			} catch (IOException e) {
				throw new RuleSecurityConfigurationException(
						"Error reading BSH file " + CONFIG_BSH + ".", e);
			} catch (EvalError e) {
				throw new RuleSecurityConfigurationException(
						"Error processing BSH file " + CONFIG_BSH + ".", e);
			}
			logger.info("The configuration defined in {} was properly loaded.",
					CONFIG_BSH);
		}
	}

	private static final class EmptyUserCredentialsResolver implements
			UserCredentialsResolver {

		@Override
		public Object getUserCredentials() {
			return null;
		}
	}
}
